/*
 * @Author: zhaoqr
 * @Date: 2024-06-17
 * @LastEditTime: 2024-07-25
 * @LastEditors: zhaoqr zhaoqr@channelsoft.com
 * @Description:
 * @FilePath: \vue3-template\src\utils\Promise.ts
 */

/**
 * 1、定义执行器executor函数，接收两个方法，一个resolve，一个reject
 * 2、new Promise可以调用then方法，也是接收两个参数resolve,reject
 * 3、调用resolve或者reject改变Promise状态，并且根据传入的值改变PromiseResult
 * 4、抛出的错误也会有改变Promise状态为rejected
 * 5、Promise状态只能被修改一次
 * 6、完善then方法的回调
 * 7、then方法处理异步返回的结果
 *    const res = new Promise((resolve: any, reject: any) => { setTimeout(() => { resolve('ok');});});
 *    res.then((res: any) => {console.log(res);}, (err: any) => { console.warn(err); });
 * 8、指定多个回调都会执行，类似下面：向callback中进行push
 *    res.then((res: any) => { console.log(res);},(err: any) => {console.warn(err); });
 *    res.then((res: any) => { alert(res);},(err: any) => {alert(err); });
 * 9、同步任务then的返回结果
 *    普通结果---const result = res.then((res: any) => { console.log(res);},(err: any) => {console.warn(err); });
 *    返回Promise--- const result = res.then((res: any) => { return new Promise((resolve: any, reject: any) => {resolve('ok');});},(err: any) => {console.warn(err); });
 * 10、异步任务then的返回结果
 *     const res = new Promise((resolve: any, reject: any) => { setTimeout(() => { resolve('ok');});});
 *     普通结果：const result = res.then((res: any) => { console.log(res);},(err: any) => {console.warn(err); });
 *     返回Promise:const result = res.then((res: any) => { return new Promise((resolve: any, reject: any) => {resolve('ok');});},(err: any) => {console.warn(err); });
 * 11、catch方法与异常穿透
 *     -- 异常穿透：就是链式调用最后需要catch方法捕获异常，无论哪个环节抛出错误。但是中间的then方法没有传递失败的回调，所以如果then方法中没有传递失败的回调，我们需要手动抛出异常，让catch方法捕获异常
 *      const res = new Promise((resolve: any, reject: any) => { setTimeout(() => { reject('ok');});});
 *      const result = res.then(value => {console.log("1111")},()=>{}).then(value => {console.log("2222")},()=>{}).catch((err: any) => {console.warn(err); });
 * 12、成功回调的穿透,第一个then调用没有提供任何回调函数，所以在res这个Promise变为fulfilled状态时，'ok'这个值被丢弃了，没有传递给下一个then。因此，后续的then方法（期望打印'2222'和'333'）实际上不会被执行，因为它们依赖于前一个then的成功结果。
 *      const res = new Promise((resolve: any, reject: any) => { setTimeout(() => { resolve('ok');});});
 *      res.then().then(value => {console.log('2222');}).then(value => {console.log('3333');})
 *      -- 正常应该输出2222 3333，但是由于第一个函数没传成功的回调，导致
 * 13、Promise的resolve方法 resolve是属于函数对象的不是属于实例对象的
 *      -- const p = Promise.resolve("ok")
 * 14、Promise.reject
 * 15、all方法
 * 16、race方法
 * 17、then中回调异步执行
 *      const p = new Promise((resolve, reject) => { console.log('111'); resolve("ok")});
 *      p.then(value => {console.log('222');});
 *      console.log('333');
 *      -- 应该输出 111 333 222 因为then是异步的
 */

export default class Promise<T> {
  // Promise的状态，初始值为pending，当调用resolve或reject后，状态会变为fulfilled或rejected
  #PromiseState: string = 'pending';

  // Promise的结果值，初始值为null，当调用resolve后，结果值会变为resolve的参数值，当调用reject后，结果值会变为reject的参数值
  #PromiseResult: any = null;

  #callbacks: Array<{ resolve?: (value: T) => void; reject?: (err: any) => void }> = [];

  constructor(executor: (resolve: (value: T) => void, reject: (error: any) => void) => void) {
    const resolve = (value: T) => {
      if (this.#PromiseState !== 'pending') {
        return;
      }
      this.#PromiseState = 'fulfilled';
      this.#PromiseResult = value;
      if (this.#callbacks.length) {
        setTimeout(() => {
          this.#callbacks.forEach(callback => {
            if (callback.resolve) {
              callback.resolve(value);
            }
          });
        });
      }
    };
    const reject = (err: any) => {
      if (this.#PromiseState !== 'pending') {
        return;
      }
      this.#PromiseState = 'rejected';
      this.#PromiseResult = err;
      if (this.#callbacks.length) {
        setTimeout(() => {
          this.#callbacks.forEach(callback => {
            if (callback.reject) {
              callback.reject(err);
            }
          });
        })
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  static resolve(value?: any) {
    return new Promise((resolve: any, reject: any) => {
      if (value instanceof Promise) {
        value.then(resolve, reject);
        // 两种都可以
        // value.then(
        //   res => {
        //     resolve(res);
        //   },
        //   rej => {
        //     reject(rej);
        //   }
        // );
      } else {
        resolve(value);
      }
    });
  }
  static reject(err?: any) {
    return new Promise((resolve: any, reject: any) => {
      // reject返回永远都是失败的
      reject(err);
    });
  }
  then(resolve?: (value: T) => void, reject?: (err: any) => void) {
    // 对于未传失败的回调，应该为其添加一个失败回调
    if (!reject) {
      reject = (err: any) => {
        throw err;
      };
    }
    // 对于未传成功的回调，创建一个默认的
    if (!resolve) {
      resolve = value => value;
    }
    return new Promise((res, rej) => {
      const handleResult = (status: Function) => {
        try {
          const result: any = status(this.#PromiseResult);
          if (result instanceof Promise) {
            result.then(
              v => {
                res(v);
              },
              r => {
                rej(r);
              }
            );
          } else {
            res(result);
          }
        } catch (error) {
          rej(error);
        }
      };
      if (this.#PromiseState == 'fulfilled') {
        if (resolve) {
          setTimeout(() => {
            handleResult(resolve);
          });
        }
      }
      if (this.#PromiseState == 'rejected') {
        if (reject) {
          setTimeout(() => {
            handleResult(reject);
          });
        }
      }
      // 如果是异步的，将两个回调保存，当状态改变的时候执行
      if (this.#PromiseState == 'pending') {
        try {
          this.#callbacks.push({
            resolve: () => {
              try {
                if (resolve) {
                  handleResult(resolve);
                }
              } catch (error) {
                rej(error);
              }
            },
            reject: () => {
              try {
                if (reject) {
                  handleResult(reject);
                }
              } catch (error) {
                rej(error);
              }
            },
          });
        } catch (error) {
          rej(error);
        }
      }
    });
  }
  // catch方法是失败的回调
  catch(reject: (err: any) => void) {
    return this.then(undefined, reject);
  }
  // all方法
  static all(Promises: Array<any>) {
    return new Promise((resolve, reject) => {
      let result: Array<any> = [];
      let count = 0;
      for (let i = 0; i < Promises.length; i++) {
        if (Promises[i] instanceof Promise) {
          Promises[i].then(
            (value: any) => {
              result[i] = value;
              count++;
              if (count == Promises.length) {
                resolve(result);
              }
            },
            (err: any) => {
              reject(err);
            }
          );
        } else {
          result[i] = Promises[i];
          count++;
          if (count == Promises.length) {
            resolve(result);
          }
        }
      }
    });
  }
  // race方法
  static race(Promises: Array<any>) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < Promises.length; i++) {
        if (Promises[i] instanceof Promise) {
          Promises[i].then(
            (value: any) => {
              resolve(value);
            },
            (err: any) => {
              reject(err);
            }
          );
        } else {
          resolve(Promises[i]);
        }
      }
    });
  }
  finally(callback: () => void) {
    return this.then(
      () => {
        callback();
      },
      () => {
        callback();
      }
    );
  }
}



